package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.Constants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.entity.DeviceData;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.job.Content;
import com.zzyl.mapper.DeviceDataMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.IotService;
import com.zzyl.vo.DeviceDataVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IotServiceImpl implements IotService {
    @Autowired
    private AliIoTConfigProperties iotProp;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private Client client;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Override
    public void syncProductList() {
        int page = 1;
        while(true){
            //调用sdk方法，请求iot平台，获取数据
            QueryProductListRequest request = new QueryProductListRequest();
            request.setCurrentPage(page);
            request.setPageSize(1);
            request.setIotInstanceId(iotProp.getIotInstanceId());
            QueryProductListResponse response = null;
            try {
                response = client.queryProductList(request);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //判断响应是否为空
            if (response == null){
                log.error("获取数据失败");
                throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
            }
            //判断响应是否成功
            Boolean b = response.getBody().getSuccess();
            if (!b){
                log.error("获取响应失败");
                throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
            }
            QueryProductListResponseBody.QueryProductListResponseBodyData data = response.getBody().getData();
            QueryProductListResponseBody.QueryProductListResponseBodyDataList list = data.getList();
            List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfoList = list.getProductInfo();
            for (QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo info : productInfoList) {
                //存入redis 1个可以对象一个产品的集合 key -> 产品的唯一标识 id data
                redisTemplate.opsForHash().put("iot:product",info.getProductKey(), JSONUtil.toJsonStr(info));
            }
            if (data.getPageCount() > data.getCurrentPage()){
                page++;
            }else {
                break;
            }
        }
    }

    @Override
    public List<ProductVo> selectAllProductList() {
        //只是创建了对象 并没有访问redis
        BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps("iot:product");
        //获取里面的对象
        List<String> values = ops.values();
        //处理集合将每个字符串转成对象并收集到集合中
        List<ProductVo> voList = values.stream()
                .map(str -> {
                    return JSONUtil.toBean(str, ProductVo.class);
                })
                .collect(Collectors.toList());
        return voList;
    }

    @Override
    public void registerDevice(DeviceDto dto) {
        //判断设备名称是否存在
        int count = deviceMapper.selectByDeviceName(dto.getDeviceName());
        //判断设备数量 >0 表示已经存在 抛异常
        if (count > 0){
            log.error("设备已经存在");
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //新增设备到IOT平台
        RegisterDeviceRequest request = new RegisterDeviceRequest();
        //设置设备的属性
        request.setIotInstanceId(iotProp.getIotInstanceId());
        request.setDeviceName(dto.getDeviceName());
        request.setNickname(dto.getNickname());
        request.setProductKey(dto.getProductKey());
        RegisterDeviceResponse response = null;
        try {
            response = client.registerDevice(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (response == null || !response.getBody().getSuccess()){
            log.error("新增设备失败");
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //获取产品名称
        String iotId = response.getBody().getData().getIotId();
        BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps("iot:product");
        String json = hashOps.get(dto.getProductKey());
        ProductVo productVo = JSONUtil.toBean(json, ProductVo.class);
        //转成device对象
        Device device = BeanUtil.toBean(dto, Device.class);
        //设置产品名称
        device.setProductName(productVo.getProductName());
        device.setIotId(iotId);
        device.setHaveEntranceGuard(0);
        //判断位置 0 代表随身设备 1代表固定设备
        if (dto.getLocationType() == 0){
            device.setPhysicalLocationType(-1);
        }
        try {
            //保存数据到数据库
            int num = deviceMapper.insert(device);
            if (num == 0){
                log.error("保存设备失败");
                throw new BaseException(BasicEnum.DEVICE_SAVE_FAIL);
            }
        }catch (Exception e){
            e.printStackTrace();
            //保存失败 删除IOT新增设备
            DeleteDeviceRequest req = new DeleteDeviceRequest();
            req.setIotId(iotId);
            req.setIotInstanceId(iotProp.getIotInstanceId());
            try {
                DeleteDeviceResponse res = client.deleteDevice(req);
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

    @Override
    public PageResponse<DeviceVo> findByPage(DevicePageQueryDto dto) {
        PageHelper.startPage(dto.getPageNum(),dto.getPageSize());
        List<Device> deviceList = deviceMapper.findByPage(dto);
        Page<Device> page = (Page<Device>) deviceList;
        return PageResponse.of(page, DeviceVo.class);
    }

    @Override
    public DeviceVo queryDeviceDetail(DeviceDto dto) {
        //查询iot平台数据
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotId(dto.getIotId());
        request.setIotInstanceId(iotProp.getIotInstanceId());
        QueryDeviceDetailResponse response = null;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (response == null || !response.getBody().getSuccess()){
            log.error("查询的设备不存在");
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);
        }
        //获取iot设备的详细信息
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();
        //强转为DeviceVo
        DeviceVo deviceVo = BeanUtil.toBean(data, DeviceVo.class);
        //获取数据库中该设备的信息
        Device device = deviceMapper.selectByIotId(dto.getIotId());
        //合并两者的信息
        BeanUtils.copyProperties(device,deviceVo);
        return deviceVo;
    }

    @Override
    public void insert(Content content) {
        //判断设备是否存在
        Device device = deviceMapper.selectByIotId(content.getIotId());
        if (device == null){
            log.error("该设备不存在");
        }
        //获取IOT数据中的每一项功能项
        Map<String, Content.Item> items = content.getItems();
        ArrayList<DeviceData> list = new ArrayList<>();
        //遍历每一项
        items.forEach((key,val) -> {
            //创建对象
            DeviceData  deviceData = DeviceData.builder()
                    .deviceName(device.getDeviceName())
                    .iotId(content.getIotId())
                    .nickname(device.getNickname())
                    .productKey(device.getProductKey())
                    .productName(device.getProductName())
                    .functionId(key)
                    .accessLocation(device.getBindingLocation())
                    .locationType(device.getLocationType())
                    .physicalLocationType(device.getPhysicalLocationType())
                    .deviceDescription(device.getDeviceDescription())
                    .dataValue(String.valueOf(val.getValue()))
                    .alarmTime(LocalDateTimeUtil.of(val.getTime()))
                    .build();
            list.add(deviceData);
        });
        //将最后一条数据存入redis
        List<DeviceDataVo> dataVoList = BeanUtil.copyToList(list, DeviceDataVo.class);
        redisTemplate.opsForHash().put(Constants.DEVICE_LASTDATA_CACHE_KEY,content.getIotId(),JSONUtil.toJsonStr(dataVoList));
        //批量添加
        deviceDataMapper.batchInsert(list);
    }

}
